/* Copyright (c) [2025] [zhi1208@126.com]
 * SPDX-License-Identifier: MIT
 */

/*********************
 *      INCLUDES
 *********************/
#include <time.h>

#include "lvgl.h"
#include "hmi_translations.h"
#include "hmi_hal.h"
#include "hmi_subjects.h"

/*********************
 *      DEFINES
 *********************/
#define tostr(x) (#x)

/**********************
 *      TYPEDEFS
 **********************/

/**********************
 *  STATIC PROTOTYPES
 **********************/
void dt_subj_group_init();
void weather_subj_group_init();

static void translations_subj_observer_cb(lv_observer_t *observer, lv_subject_t *subject);
static void auto_dt_observer_cb(lv_observer_t *observer, lv_subject_t *subject);
static void led_strip_sw_observer_cb(lv_observer_t *observer, lv_subject_t *subject);
static void led_strip_normal_observer_cb(lv_observer_t *observer, lv_subject_t *subject);
static void led_strip_color_observer_cb(lv_observer_t *observer, lv_subject_t *subject);
static void led_strip_rainbow_observer_cb(lv_observer_t *observer, lv_subject_t *subject);
static void led_strip_brightness_observer_cb(lv_observer_t *observer, lv_subject_t *subject);
static void led_strip_hue_observer_cb(lv_observer_t *observer, lv_subject_t *subject);

static void dt_update_timer_cb(lv_timer_t *t);
static void weather_update_timer_cb(lv_timer_t *t);

static void subject_init_int_form_nvs(lv_subject_t *subject, int32_t value, const char *name);

/**********************
 *  STATIC VARIABLES
 **********************/

static lv_subject_t year_subj;
static lv_subject_t month_subj;
static lv_subject_t day_subj;
static lv_subject_t weekday_subj;
static lv_subject_t hour_subj;
static lv_subject_t minute_subj;
static lv_subject_t *dt_subj_list[] = {
    &year_subj,
    &month_subj,
    &day_subj,
    &weekday_subj,
    &hour_subj,
    &minute_subj};

static lv_subject_t city_subj;
static lv_subject_t text_day_subj;
static lv_subject_t code_day_subj;
static lv_subject_t text_night_subj;
static lv_subject_t code_night_subj;
static lv_subject_t high_subj;
static lv_subject_t low_subj;
static lv_subject_t precip_subj;
static lv_subject_t wind_scale_subj;
static lv_subject_t humidity_subj;
static lv_subject_t *weather_subj_list[] = {
    &city_subj,
    &text_day_subj,
    &code_day_subj,
    &text_night_subj,
    &code_night_subj,
    &high_subj,
    &low_subj,
    &precip_subj,
    &wind_scale_subj,
    &humidity_subj};

/**********************
 *      MACROS
 **********************/

/**********************
 *   GLOBAL FUNCTIONS
 **********************/
lv_subject_t hmi_wifi_connect_subj;
lv_subject_t hmi_wifi_subj;

lv_subject_t hmi_bluetooth_subj;

lv_subject_t hmi_translations_subj;

lv_subject_t hmi_auto_dt_subj;

lv_subject_t hmi_led_strip_sw_subj;
lv_subject_t hmi_led_strip_normal_subj;
lv_subject_t hmi_led_strip_color_subj;
lv_subject_t hmi_led_strip_rainbow_subj;
lv_subject_t hmi_led_strip_brightness_subj;
lv_subject_t hmi_led_strip_hue_subj;

lv_subject_t hmi_dt_subj_group;
lv_subject_t hmi_weather_subj_group;

void hmi_subjects_init()
{
#if (LVGL_VERSION_MAJOR >= 9 && LVGL_VERSION_MINOR >= 4 && LVGL_VERSION_PATCH >= 0)
    hmi_translations_init();
#endif

    lv_subject_init_int(&hmi_wifi_connect_subj, 0);
    lv_subject_init_int(&hmi_wifi_subj, 0);

    lv_subject_init_int(&hmi_bluetooth_subj, 0);

    subject_init_int_form_nvs(&hmi_translations_subj, 0, "translations");

    subject_init_int_form_nvs(&hmi_auto_dt_subj, 1, "auto_dt");

    subject_init_int_form_nvs(&hmi_led_strip_sw_subj, 0, "strip_sw");
    subject_init_int_form_nvs(&hmi_led_strip_normal_subj, 0, "strip_normal");
    subject_init_int_form_nvs(&hmi_led_strip_color_subj, 1, "strip_color");
    subject_init_int_form_nvs(&hmi_led_strip_rainbow_subj, 0, "strip_rainbow");
    subject_init_int_form_nvs(&hmi_led_strip_brightness_subj, 70, "strip_brt");
    subject_init_int_form_nvs(&hmi_led_strip_hue_subj, 0, "strip_hue");

    dt_subj_group_init();
    weather_subj_group_init();

    lv_subject_add_observer(&hmi_translations_subj, translations_subj_observer_cb, NULL);
    lv_subject_add_observer(&hmi_auto_dt_subj, auto_dt_observer_cb, NULL);
    lv_subject_add_observer(&hmi_led_strip_sw_subj, led_strip_sw_observer_cb, NULL);
    lv_subject_add_observer(&hmi_led_strip_normal_subj, led_strip_normal_observer_cb, NULL);
    lv_subject_add_observer(&hmi_led_strip_color_subj, led_strip_color_observer_cb, NULL);
    lv_subject_add_observer(&hmi_led_strip_rainbow_subj, led_strip_rainbow_observer_cb, NULL);
    lv_subject_add_observer(&hmi_led_strip_brightness_subj, led_strip_brightness_observer_cb, NULL);
    lv_subject_add_observer(&hmi_led_strip_hue_subj, led_strip_hue_observer_cb, NULL);

    lv_timer_t *dt_update_timer = lv_timer_create(dt_update_timer_cb, 1000, NULL);
    lv_timer_set_repeat_count(dt_update_timer, -1);
    lv_timer_ready(dt_update_timer);

    lv_timer_t *weather_update_timer = lv_timer_create(weather_update_timer_cb, 1000 * 60 * 10, NULL);
    lv_timer_set_repeat_count(weather_update_timer, -1);
    lv_timer_ready(weather_update_timer);
}

/**********************
 *   STATIC FUNCTIONS
 **********************/
void dt_subj_group_init()
{
    lv_subject_init_int(&year_subj, 2025);
    lv_subject_init_int(&month_subj, 7);
    lv_subject_init_int(&day_subj, 27);
    lv_subject_init_int(&weekday_subj, 1);
    lv_subject_init_int(&hour_subj, 0);
    lv_subject_init_int(&minute_subj, 0);
    lv_subject_init_group(&hmi_dt_subj_group, dt_subj_list, sizeof(dt_subj_list) / sizeof(lv_subject_t *));
}

void weather_subj_group_init()
{
    static char city[HMI_WEATHER_CITY_NAME_LEN_MAX];
    static char text_day[HMI_WEATHER_TEXT_LEN_MAX];
    static char text_night[HMI_WEATHER_TEXT_LEN_MAX];

#ifdef LV_PORT_VS_CODE

#if (LVGL_VERSION_MAJOR >= 9 && LVGL_VERSION_MINOR >= 4 && LVGL_VERSION_PATCH >= 0)
    lv_subject_init_string(&city_subj, city, NULL, HMI_WEATHER_CITY_NAME_LEN_MAX, lv_tr("北京"));
#else
    lv_subject_init_string(&city_subj, city, NULL, HMI_WEATHER_CITY_NAME_LEN_MAX, "北京");
#endif

#if (LVGL_VERSION_MAJOR >= 9 && LVGL_VERSION_MINOR >= 4 && LVGL_VERSION_PATCH >= 0)
    lv_subject_init_string(&text_day_subj, text_day, NULL, HMI_WEATHER_TEXT_LEN_MAX, lv_tr("晴"));
#else
    lv_subject_init_string(&text_day_subj, text_day, NULL, HMI_WEATHER_TEXT_LEN_MAX, "晴");
#endif

#if (LVGL_VERSION_MAJOR >= 9 && LVGL_VERSION_MINOR >= 4 && LVGL_VERSION_PATCH >= 0)
    lv_subject_init_string(&text_night_subj, text_night, NULL, HMI_WEATHER_TEXT_LEN_MAX, lv_tr("晴"));
#else
    lv_subject_init_string(&text_night_subj, text_night, NULL, HMI_WEATHER_TEXT_LEN_MAX, "晴");
#endif

    lv_subject_init_int(&code_day_subj, 0);
    lv_subject_init_int(&code_night_subj, 0);
    lv_subject_init_int(&high_subj, 28);
    lv_subject_init_int(&low_subj, 22);
    lv_subject_init_int(&precip_subj, 0);
    lv_subject_init_int(&wind_scale_subj, 1);
    lv_subject_init_int(&humidity_subj, 67);

#else /* LV_PORT_VS_CODE */

#if (LVGL_VERSION_MAJOR >= 9 && LVGL_VERSION_MINOR >= 4 && LVGL_VERSION_PATCH >= 0)
    lv_subject_init_string(&city_subj, city, NULL, HMI_WEATHER_CITY_NAME_LEN_MAX, lv_tr("未知"));
#else
    lv_subject_init_string(&city_subj, city, NULL, HMI_WEATHER_CITY_NAME_LEN_MAX, "未知");
#endif

#if (LVGL_VERSION_MAJOR >= 9 && LVGL_VERSION_MINOR >= 4 && LVGL_VERSION_PATCH >= 0)
    lv_subject_init_string(&text_day_subj, text_day, NULL, HMI_WEATHER_TEXT_LEN_MAX, lv_tr("未知"));
#else
    lv_subject_init_string(&text_day_subj, text_day, NULL, HMI_WEATHER_TEXT_LEN_MAX, "未知");
#endif

#if (LVGL_VERSION_MAJOR >= 9 && LVGL_VERSION_MINOR >= 4 && LVGL_VERSION_PATCH >= 0)
    lv_subject_init_string(&text_night_subj, text_night, NULL, HMI_WEATHER_TEXT_LEN_MAX, lv_tr("未知"));
#else
    lv_subject_init_string(&text_night_subj, text_night, NULL, HMI_WEATHER_TEXT_LEN_MAX, "未知");
#endif

    lv_subject_init_int(&code_day_subj, 99);
    lv_subject_init_int(&code_night_subj, 99);
    lv_subject_init_int(&high_subj, 0);
    lv_subject_init_int(&low_subj, 0);
    lv_subject_init_int(&precip_subj, 0);
    lv_subject_init_int(&wind_scale_subj, 0);
    lv_subject_init_int(&humidity_subj, 0);

#endif /* LV_PORT_VS_CODE */

    lv_subject_init_group(&hmi_weather_subj_group, weather_subj_list, sizeof(weather_subj_list) / sizeof(lv_subject_t *));
}

static void translations_subj_observer_cb(lv_observer_t *observer, lv_subject_t *subject)
{
    LV_UNUSED(observer);

    int32_t lang = lv_subject_get_int(subject);

    if (lang == 0)
    {
#if (LVGL_VERSION_MAJOR >= 9 && LVGL_VERSION_MINOR >= 4 && LVGL_VERSION_PATCH >= 0)
        lv_translation_set_language("zh");
#endif
    }
    else if (lang == 1)
    {
#if (LVGL_VERSION_MAJOR >= 9 && LVGL_VERSION_MINOR >= 4 && LVGL_VERSION_PATCH >= 0)
        lv_translation_set_language("en");
#endif
    }

    hmi_hal_nvs_set("translations", lang);
}

static void auto_dt_observer_cb(lv_observer_t *observer, lv_subject_t *subject)
{
    LV_UNUSED(observer);

    int32_t auto_dt = lv_subject_get_int(subject);

    if (auto_dt)
        hmi_hal_auto_dt_enable();
    else
        hmi_hal_auto_dt_disable();

    hmi_hal_nvs_set("auto_dt", auto_dt);
}

static void led_strip_sw_observer_cb(lv_observer_t *observer, lv_subject_t *subject)
{
    LV_UNUSED(observer);
    LV_UNUSED(subject);

    hmi_hal_nvs_set("strip_sw", lv_subject_get_int(&hmi_led_strip_sw_subj));
}
static void led_strip_normal_observer_cb(lv_observer_t *observer, lv_subject_t *subject)
{
    LV_UNUSED(observer);
    LV_UNUSED(subject);

    hmi_hal_nvs_set("strip_normal", lv_subject_get_int(&hmi_led_strip_normal_subj));
}
static void led_strip_color_observer_cb(lv_observer_t *observer, lv_subject_t *subject)
{
    LV_UNUSED(observer);
    LV_UNUSED(subject);

    hmi_hal_nvs_set("strip_color", lv_subject_get_int(&hmi_led_strip_color_subj));
}
static void led_strip_rainbow_observer_cb(lv_observer_t *observer, lv_subject_t *subject)
{
    LV_UNUSED(observer);
    LV_UNUSED(subject);

    hmi_hal_nvs_set("strip_rainbow", lv_subject_get_int(&hmi_led_strip_rainbow_subj));
}
static void led_strip_brightness_observer_cb(lv_observer_t *observer, lv_subject_t *subject)
{
    LV_UNUSED(observer);
    LV_UNUSED(subject);

    hmi_hal_nvs_set("strip_brt", lv_subject_get_int(&hmi_led_strip_brightness_subj));
}
static void led_strip_hue_observer_cb(lv_observer_t *observer, lv_subject_t *subject)
{
    LV_UNUSED(observer);
    LV_UNUSED(subject);

    hmi_hal_nvs_set("strip_hue", lv_subject_get_int(&hmi_led_strip_hue_subj));
}

static void dt_update_timer_cb(lv_timer_t *t)
{
    LV_UNUSED(t);

    struct tm *local_tm = hmi_hal_dt_get();

    if (!local_tm)
        return;

    lv_subject_set_int(&year_subj, local_tm->tm_year + 1900);
    lv_subject_set_int(&month_subj, local_tm->tm_mon + 1);
    lv_subject_set_int(&day_subj, local_tm->tm_mday);
    lv_subject_set_int(&weekday_subj, local_tm->tm_wday);
    lv_subject_set_int(&hour_subj, local_tm->tm_hour);
    lv_subject_set_int(&minute_subj, local_tm->tm_min);

    lv_free(local_tm);
}

static void weather_update_timer_cb(lv_timer_t *t)
{
    LV_UNUSED(t);

    hmi_hal_weather_get();
}

static void subject_init_int_form_nvs(lv_subject_t *subject, int32_t value, const char *name)
{
    int32_t buf;
    if (hmi_hal_nvs_get(name, &buf))
        lv_subject_init_int(subject, buf);
    else
        lv_subject_init_int(subject, value);
}